<?php
/**
 * Renderiza elementos html de acordo com os dados do modelo enviado como parâmetro
 * 
 * @author Cristiano M. Gomes <cmgomes.es@gmail.com>
 *
 */
class Template {
	/**
	 * Conteudo HTML a ser exibito na tela
	 *
	 * @var string
	 */
    private $pagina;
    
    /**
     * propriedade singleton do objeto
     *
     * @var Template
     */
    private static $Instancia;

    /**
     * Function Singleton para instanciamento único da classe Aplicação
     */ 
    public static function Instanciar(){
        if(!self::$Instancia){
            self::$Instancia = new Template;
            return self::$Instancia;
        }
        return self::$Instancia;
    }

    /**
     * Método construtor do objeto
     * apenas inclui as bibliotecas externas de manipulação de DOM HTML
     */
    function __construct(){
    	include DIR_FRAMEWORK_INCLUDES . 'simple_html_dom.php';
    }

    /**
     * Carreta o arquivo html da página solicitada, e também busca pelas master pages integrando tudo em um único documento virtual
     * e armazenando em forma de string na propriedade pagina
     *
     * @param string $nome
     * @return string	|	Boolean
     */
    public function CarregaHtml($nome){

            $file = DIR_HTML . strtolower($nome);
            $pag = file_get_contents($file);
            
            if($pag){
                while($mestre = $this->PossuiMaster($pag)){

                    $file = DIR_MASTER . strtolower($mestre[1]) . '.html';
                    $conteudo_mestre = file_get_contents($file);
                    $pag = str_replace('<conteudo>', $mestre[0], $conteudo_mestre);
                }
                $this->pagina = $pag;
                return $pag;
            }
            return false;
    }
    
    /**
     * Procura pelas tags nos htmls e troca pelos valores contidos em Controle::TrocaConteudo
     * @param Controle $control
     */
    public function Renderizar(Controle $control){
    	//-------Trocando as tags dinâmicas do conteudo
        $novo_conteudo = '';
        $conteudo = $control->Conteudo();

        if(sizeof($control->GetTrocaConteudo()) > 0){
            foreach($control->GetTrocaConteudo() as $key => $val){
                $novo_conteudo = str_replace($key, $val, $conteudo);
                $conteudo = $novo_conteudo;
            }
        }

        //-------- Escondendo elementos desejados
        $hidden_elements = $control->GetElementosHidden();
        $dom = $this->StrParaHtml($conteudo);

        foreach($hidden_elements as $id){
        	$elemento = $dom->getElementById($id);
        	$elemento->setAttribute('style', 'display: none;');
        }
        $conteudo = $dom->save();
        
        //-------- Setando valores nos inputs
        $tmp_valores = $control->GetInputValores();
        foreach($tmp_valores as $id => $valor){
        	$tmp_element = $dom->getElementById($id);
        	$tmp_element->setAttribute('value', $valor);
        }
        $conteudo = $dom->save();
       
        //-------- Verificando a existencia de datagrid e gerando caso necessário

        if(strpos($conteudo, '%data-grid%')){
        	$datagrid = DataGrid::Instanciar();
        	$datagrid->AjustaControle($control);
        	$lista = $datagrid->GerarDataGrid();
        	$conteudo = str_replace('%data-grid%', $lista, $conteudo);

        }
        //-------- prosseguindo o processamento
        $this->pagina = $this->DefaultRender($conteudo);
        if(sizeof($control->GetInputValores()) > 0)
        	$this->MudaValor($control->GetInputValores());
    }
    
    /**
     * Procura por tags padrões inseridas no html e troca por valores de Sessao que atualmente são:
     * 
     * Ssessao::GetVarSessao('id');
     * Sessao::GetVarSessao('usuario');
     * Sessao::GetVarSessao('logado');
     * 
     * @return void
     */
    public function DefaultRender($conteudo){
        $ses = Sessao::Instanciar();
        $array = array('%usuario%' => $ses->GetVarSessao('usuario'),
                       '%userid%'  => $ses->GetVarSessao('userid'));
        foreach($array as $key => $val){
                $novo_conteudo = str_replace($key, $val, $conteudo);
                $conteudo = $novo_conteudo;
        }
        return $novo_conteudo;
    }
    
    /**
     * Método responsável pela inserção de css e js padrães da página e também substituir 
     * as tags especiais por caminhos virtuais válido do sistema.
     */  
    public function InsereComponentes(Controle $control){
    	
        $conteudo = $control->Conteudo();
        $controle = $control->GetSistema()->GetPaginaAtual()->Nome();
        $javascript = $control->GetSistema()->GetPaginaAtual()->Javascript();

        $tmp_css = ROOT_CSS . $controle . '.css';
        $tmp_js = ROOT_JS . $javascript;

        $css = (file_exists($tmp_css))? "<link rel='stylesheet' type='text/css' href='$tmp_css' />" : '';
        $js = (file_exists($tmp_js))? "<script type='text/javascript' src='$tmp_js'></script>" : '';

        $array = array('%CSS%'  =>  $css,
                       '%JS%'   =>  $js,
                       '%IMG%'  =>  ROOT_IMG,
                       '%SWF%'  =>  ROOT_SWF,
        			   '%titulo-pagina%' => $control->Titulo());

        foreach($array as $texto => $valor){
            $novo_conteudo = str_replace($texto, $valor, $conteudo);
            $conteudo = $novo_conteudo;
        }

        $control->Conteudo($conteudo);
    }

    /**
     * Função para uso interno
     * Verifica se o arquivo html carregado possui vinculo com alguma master page
     *
     * @param string $conteudo
     * @return array	| 	Boolean
     */
    public function PossuiMaster($conteudo){
        $busca = '<%([\w]*)\=([\w]*)%>';
        $item = preg_match($busca, $conteudo, $founds);

        if($item){
            $novo_conteudo = str_replace("<{$founds[0]}>", '', $conteudo);
            $array = array($novo_conteudo, $founds[2]);
            return $array;
        }
        return false;
    }

    /**
     * Envia conteudo da propriedade pagina para o navegador
     */
    public function Show(){
    	echo $this->pagina;
    }

	/**
	 * Com base no modelo cadastrado e/ou nas propriedades do controle, seta os inputs de tela
	 * Ignorando os inputs tipo File
	 * 
	 * @return void
	 */
    public function ConfiguraTelaPorModelo(Controle $control){
    	$mod = $control->Modelo();
    	$gets = get_class_methods($mod);
    	$dom = $this->StrParaHtml($this->pagina);
    	
		//$textarea_index = 0;
		$radio_fill = false;

        for($i = 0; $i < sizeof($gets); $i++){
            if(strpos($gets[$i], 'get_') == 0){
            	
                $input = $dom->getElementById( str_replace('get_', '', $gets[$i]) );
                if($input){
                	$metodo = $gets[$i];
                	
					//Tratando os inputs type: text, password, hidden
					$attr_type = $input->getAttribute('type');
					if($attr_type == 'text' || $attr_type == 'password' || $attr_type == 'hidden'){
						$input->setAttribute('value', $mod->$metodo());
					}

					//Tratando os inputs type: radio
					if($attr_type == 'radio'){
						if(!$radio_fill){
							$radios = $input->getElementsByTagName('radio');
							foreach($radios as $radio){
								if($radio->getAttribute('value') == $mod->metodo()){
									$radio->setAttribute('checked', 'checked');
								}
							}
							$radio_fill = true;
						}
					}
					
					//Tratando os inputs type: checkbox
					if($attr_type == 'checkbox'){
						$nome_metodo = str_replace('get_', '', $metodo);
						$selector = 'input[name="' . $nome_metodo . '"]';
						$checkboxes = $dom->find($selector);

						foreach($checkboxes as $checkbox){
	            	   		if($checkbox->getAttribute('name') == $nome_metodo){
	            	   			if($mod->$metodo()){
	            	   				$checkbox->setAttribute('checked', 'checked');
	            	   			}
	            	   		}
	                	}
					}

					//Tratando os textareas
                	if($input->hasAttribute('rows')){ 
                	   $nome_metodo = str_replace('get_', '', $metodo);
                	   $selector = 'textarea[name="' . $nome_metodo . '"]';
                	   $textareas = $dom->find($selector);

                	   if($textareas instanceof simple_html_dom_node){
                	   		if($textareas->getAttribute('name') == $nome_metodo)
                	   			$textareas->innertext = $mod->$metodo();
                	   }else{
	                	   foreach($textareas as $textarea){
	                	   		if($textarea->getAttribute('name') == $nome_metodo){
	                	   			$textarea->innertext = $mod->$metodo();
	                	   		}
	                	   }
                	   }
                	}

                	//Tratando os selects
                	if($input->hasAttribute('title') && $input->getAttribute('title') == 'select'){ 
                	   
                	}

                }
            }
        }

        $this->pagina = $dom->save();
    }

    /**
     * Futuro método para configuração da tela com base nas propriedades do controle de tela.
     */
    public function ConfiguraTelaPorControle(){
    	
    }

    /**
     * Caso haja alguma mensagem registrada na classe Menssagem, este método aplica a mensagem
     * no onload da página para visualização do usuário
     */
    public function ConfiguraMensagem(){
    	if(sizeof(Mensagens::GetMensagem()) > 0){
    		$msn = Mensagens::GetMensagem();
    		$funcao = "Sofia.Alert('{$msn['titulo']}','{$msn['conteudo']}');";

    		$dom = $this->StrParaHtml($this->pagina);

    		$body = $dom->getElementByTagName('body');
    		$body->setAttribute('onload', $funcao);
    		
    		$this->pagina = $dom->save();
    	}
    }

	/**
     * Configura uma função javascript para ser chamada no onload da página
     * Essa função só é chamada se nenhuma mensagem for enviada. Caso contrario ela não é executada
     * 
     * @param Controle
     * @return void
     */
    public function ConfiguraOnload(Controle $ctrl){
    	if(sizeof(Mensagens::GetMensagem()) == 0){
	    	$onload = $ctrl->GetOnload();
	    	if(sizeof($onload) > 0){
	    		$dom = $this->StrParaHtml($this->pagina);
	
	    		$body = $dom->getElementByTagName('body');
	    		$body->setAttribute('onload', $onload);
	
	    		$this->pagina = $dom->save();
	    	}
    	}
    }
    
    /**
     * Da parser na string retornando objeto HTML
     * @param simple_html_document
     */
    public function StrParaHtml($string){
    	return str_get_html($string);
    }

    /**
     * Altera o valor de elementos que possuem atributo value
     *
     * @param string $id
     * @param string $valor
     */
    public function MudaValor(array $valores){
    	$dom = $this->StrParaHtml($this->pagina);
		foreach($valores as $id => $valor){
			$elemento = $dom->getElementById($id);
			$elemento->setAttribute('value', $valor);
		}
    	$this->pagina = $dom->save();
    }
}